package com.kindey.httpclientdemo.util;

import org.apache.commons.io.IOUtils;
import org.springframework.util.StringUtils;

import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

/**
 * HttpURLconnection工具类
 * 提供get、post请求封装方法
 *
 * @author kindey.s [kindey123@163.com]
 * @date 2020/6/6
 * @since 1.0
 */
public final class HttpURLconnectionUtil {

    /**
     * 发送get请求
     *
     * @param url                请求路径
     * @param connectTimeout     连接超时时间，
     *                           单位ms，
     *                           设置为0使用默认值。
     * @param readTimeout        读取超时时间，
     *                           单位ms，
     *                           设置为0使用默认值。
     * @param requestHeaderParam 请求头参数
     * @return InputStream 请求返回信息，二进制字节流
     * @throw IOException
     * @author Kindey.S [kindey123@163.com]
     * @date 2020/6/6 13:01
     */
    public static InputStream sendGet(String url, int connectTimeout, int readTimeout
            , HashMap<String, String> requestHeaderParam) throws IOException {
        InputStream in;
        URL httpUrl = new URL(url);
        HttpURLConnection connection = (HttpURLConnection) httpUrl.openConnection();
        connection.setRequestMethod("GET");
        //设置连接超时时间
        if (connectTimeout != 0) {
            connection.setConnectTimeout(connectTimeout);
        }
        //设置读取超时时间
        if (readTimeout != 0) {
            connection.setReadTimeout(readTimeout);
        }
        //这只requestHead参数
        for (Map.Entry<String, String> entry : requestHeaderParam.entrySet()) {
            connection.setRequestProperty(entry.getKey(), entry.getValue());
        }
        //发起请求
        connection.connect();
        //获取返回信息
        in = connection.getInputStream();
        return in;
    }

    /**
     * 发送get请求
     * 简化使用，不设置连接超时时间与读取超时时间
     *
     * @param url                请求路径
     * @param requestHeaderParam 请求头参数
     * @return InputStream 请求返回信息，二进制字节流
     * @throw IOException
     * @author Kindey.S [kindey123@163.com]
     * @date 2020/6/6 13:01
     */
    public static InputStream sendGet(String url, HashMap<String, String> requestHeaderParam) throws IOException {
        return sendGet(url, 0, 0, requestHeaderParam);
    }

    /**
     * 发送get请求
     * 简化使用，只设置url
     * 请求头参数默认值：
     * accept=\*\/\*
     * connection=Keep-Alive
     * Charsert=UTF-8
     * user-agent=Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)
     *
     * @param url 请求路径
     * @return InputStream 请求返回信息，二进制字节流
     * @throw IOException
     * @author Kindey.S [kindey123@163.com]
     * @date 2020/6/6 13:01
     */
    public static InputStream sendGet(String url) throws IOException {
        HashMap<String, String> headParam = new HashMap<>();
        headParam.put("accept", "*/*");
        headParam.put("connection", "Keep-Alive");
        headParam.put("Charsert", "UTF-8"); //设置请求编码
        headParam.put("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
        return sendGet(url, headParam);
    }

    /**
     * 发送get请求
     *
     * @param url                请求路径
     * @param connectTimeout     连接超时时间，
     *                           单位ms，
     *                           设置为0使用默认值。
     * @param readTimeout        读取超时时间，
     *                           单位ms，
     *                           设置为0使用默认值。
     * @param requestHeaderParam 请求头参数
     * @param charSet            流转字符串使用的编码格式
     *                           传空字符串默认UTF-8
     * @return result 请求返回信息，字节流转换后的字符串
     * @throw IOException
     * @author Kindey.S [kindey123@163.com]
     * @date 2020/6/6 13:01
     */
    public static String sendGet(String url, int connectTimeout, int readTimeout
            , HashMap<String, String> requestHeaderParam, String charSet) throws IOException {
        InputStream in = sendGet(url, connectTimeout, readTimeout, requestHeaderParam);
        //设置编码格式，默认UTF-8
        if (StringUtils.isEmpty(charSet)) {
            charSet = "UTF-8";
        }
        return IOUtils.toString(in, charSet);
    }

    /**
     * 发送get请求
     * 简化使用，不设置连接超时时间与读取超时时间
     *
     * @param url                请求路径
     * @param requestHeaderParam 请求头参数
     * @param charSet            流转字符串使用的编码格式
     *                           传空字符串默认UTF-8
     * @return result 请求返回信息，字节流转换后的字符串
     * @throw IOException
     * @author Kindey.S [kindey123@163.com]
     * @date 2020/6/6 13:01
     */
    public static String sendGet(String url, HashMap<String, String> requestHeaderParam, String charSet) throws IOException {
        return sendGet(url, 0, 0, requestHeaderParam, charSet);
    }

    /**
     * 发送get请求
     * 简化使用，只设置url
     * 请求头参数默认值：
     * accept=\*\/\*
     * connection=Keep-Alive
     * Charsert=UTF-8
     * user-agent=Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)
     *
     * @param url     请求路径
     * @param charSet 流转字符串使用的编码格式
     *                传空字符串默认UTF-8
     * @return result 请求返回信息，字节流转换后的字符串
     * @throw IOException
     * @author Kindey.S [kindey123@163.com]
     * @date 2020/6/6 13:01
     */
    public static String sendGet(String url, String charSet) throws IOException {
        HashMap<String, String> headParam = new HashMap<>();
        headParam.put("accept", "*/*");
        headParam.put("connection", "Keep-Alive");
        headParam.put("Charsert", "UTF-8"); //设置请求编码
        headParam.put("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
        return sendGet(url, headParam, charSet);
    }

    /**
     * 转换问题request的参数格式
     *
     * @param params        参数map
     * @param encode        参数内容是否encode
     * @param encodeCharSet encode参数类型的时候使用的编码格式，默认UTF-8
     * @return String
     * @throw UnsupportedEncodingException
     * @author Kindey.S [kindey123@163.com]
     * @date 2020/6/7 12:01
     */
    private static String getPathParam(HashMap<String, String> params, Boolean encode
            , String encodeCharSet) throws UnsupportedEncodingException {
        StringBuilder sb = new StringBuilder();
        if (StringUtils.isEmpty(encodeCharSet)) {
            encodeCharSet = "UTF-8";
        }
        for (Map.Entry<String, String> entry : params.entrySet()) {
            sb.append(entry.getKey());
            sb.append("=");
            if (encode) {
                sb.append(URLEncoder.encode(entry.getValue(), encodeCharSet));
            } else {
                sb.append(entry.getValue());
            }
            sb.append("&");
        }

        String result;
        if (sb.length() == 0) {
            result = "";
        } else {
            result = sb.toString().substring(0, sb.length() - 1);
        }
        return result;
    }


    /**
     * 发送post请求
     *
     * @param url                请求路径
     * @param connectTimeout     连接超时时间，
     *                           单位ms，
     *                           设置为0使用默认值。
     * @param readTimeout        读取超时时间，
     *                           单位ms，
     *                           设置为0使用默认值。
     * @param requestHeaderParam 请求头参数
     * @param pathParam          路径参数
     * @param encode             参数是否encdoe
     * @param encodeCharSet      encdoe参数使用的字符编码
     * @return InputStream 请求返回信息，二进制字节流
     * @author Kindey.S [kindey123@163.com]
     * @date 2020/6/6 17:00
     */
    public static InputStream sendPost(String url, int connectTimeout, int readTimeout
            , HashMap<String, String> requestHeaderParam, HashMap<String, String> pathParam
            , boolean encode, String encodeCharSet) throws IOException {
        InputStream in;
        URL httpUrl = new URL(url);
        HttpURLConnection connection = (HttpURLConnection) httpUrl.openConnection();
        connection.setRequestMethod("POST");
        // Post 请求不能使用缓存
        connection.setUseCaches(false);
        //设置本次连接是否自动重定向
        connection.setInstanceFollowRedirects(true);
        //设置连接超时时间
        if (connectTimeout != 0) {
            connection.setConnectTimeout(connectTimeout);
        }
        //设置读取超时时间
        if (readTimeout != 0) {
            connection.setReadTimeout(readTimeout);
        }
        //开启输入输出流，默认是关闭的，post请求需要手动开启
        connection.setDoInput(true);
        connection.setDoOutput(true);
        //这只requestHead参数
        for (Map.Entry<String, String> entry : requestHeaderParam.entrySet()) {
            connection.setRequestProperty(entry.getKey(), entry.getValue());
        }
        //开启连接
        connection.connect();
        BufferedOutputStream out = new BufferedOutputStream(connection.getOutputStream());

        String pathP = getPathParam(pathParam, encode, encodeCharSet);
        if (!StringUtils.isEmpty(pathP)) {
            out.write(pathP.getBytes());
            //关闭之前一定要刷新缓冲流。
            out.flush();
        }

        //关闭连接
        out.close();
        in = connection.getInputStream();
        return in;
    }

    /**
     * 发送post请求
     *
     * @param url                请求路径
     * @param requestHeaderParam 请求头参数
     * @param pathParam          路径参数
     * @param encode             参数是否encdoe
     * @param encodeCharSet      encdoe参数使用的字符编码
     * @return InputStream 请求返回信息，二进制字节流
     * @author Kindey.S [kindey123@163.com]
     * @date 2020/6/7 12:41
     */
    public static InputStream sendPost(String url, HashMap<String, String> requestHeaderParam
            , HashMap<String, String> pathParam, boolean encode, String encodeCharSet) throws IOException {
        return sendPost(url, 0, 0, requestHeaderParam, pathParam, encode, encodeCharSet);
    }

    /**
     * 发送post请求
     * 简化使用，只设置url
     * 请求头参数默认值：
     * accept=\*\/\*
     * connection=Keep-Alive
     * Charsert=UTF-8
     * user-agent=Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)
     *
     * @param url           请求路径
     * @param pathParam     路径参数
     * @param encode        参数是否encdoe
     * @param encodeCharSet encdoe参数使用的字符编码
     * @return InputStream 请求返回信息，二进制字节流
     * @author Kindey.S [kindey123@163.com]
     * @date 2020/6/7 12:41
     */
    public static InputStream sendPost(String url, HashMap<String, String> pathParam
            , boolean encode, String encodeCharSet) throws IOException {
        HashMap<String, String> headParam = new HashMap<>();
        headParam.put("accept", "*/*");
        headParam.put("connection", "Keep-Alive");
        headParam.put("Charsert", "UTF-8"); //设置请求编码
        headParam.put("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
        return sendPost(url, headParam, pathParam, encode, encodeCharSet);
    }

    /**
     * 发送post请求
     * 简化使用，只设置url
     * 请求头参数默认值：
     * accept=\*\/\*
     * connection=Keep-Alive
     * Charsert=UTF-8
     * user-agent=Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)
     *
     * @param url       请求路径
     * @param pathParam 路径参数
     * @return InputStream 请求返回信息，二进制字节流
     * @author Kindey.S [kindey123@163.com]
     * @date 2020/6/7 12:41
     */
    public static InputStream sendPost(String url, HashMap<String, String> pathParam) throws IOException {
        return sendPost(url, pathParam, false, "");
    }

    /**
     * 发送post请求
     *
     * @param url                请求路径
     * @param connectTimeout     连接超时时间，
     *                           单位ms，
     *                           设置为0使用默认值。
     * @param readTimeout        读取超时时间，
     *                           单位ms，
     *                           设置为0使用默认值。
     * @param requestHeaderParam 请求头参数
     * @param pathParam          路径参数
     * @param encode             参数是否encdoe
     * @param encodeCharSet      encdoe参数使用的字符编码
     * @param charSet            返回结果二进制流转字符串使用的编码格式
     * @return String 请求返回信息
     * @author Kindey.S [kindey123@163.com]
     * @date 2020/6/7 13:21
     */
    public static String sendPost(String url, int connectTimeout, int readTimeout
            , HashMap<String, String> requestHeaderParam, HashMap<String, String> pathParam
            , boolean encode, String encodeCharSet, String charSet) throws IOException {
        InputStream in = sendPost(url, connectTimeout, readTimeout, requestHeaderParam, pathParam, encode, encodeCharSet);
        //设置编码格式，默认UTF-8
        if (StringUtils.isEmpty(charSet)) {
            charSet = "UTF-8";
        }
        return IOUtils.toString(in, charSet);
    }

    /**
     * 发送post请求
     *
     * @param url                请求路径
     * @param requestHeaderParam 请求头参数
     * @param pathParam          路径参数
     * @param encode             参数是否encdoe
     * @param encodeCharSet      encdoe参数使用的字符编码
     * @param charSet            返回结果二进制流转字符串使用的编码格式
     * @return String 请求返回信息
     * @author Kindey.S [kindey123@163.com]
     * @date 2020/6/7 13:21
     */
    public static String sendPost(String url
            , HashMap<String, String> requestHeaderParam, HashMap<String, String> pathParam
            , boolean encode, String encodeCharSet, String charSet) throws IOException {
        return sendPost(url, 0, 0, requestHeaderParam, pathParam, encode, encodeCharSet, charSet);
    }

    /**
     * 发送post请求
     * 简化使用，只设置url
     * 请求头参数默认值：
     * accept=\*\/\*
     * connection=Keep-Alive
     * Charsert=UTF-8
     * user-agent=Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)
     *
     * @param url           请求路径
     * @param pathParam     路径参数
     * @param encode        参数是否encdoe
     * @param encodeCharSet encdoe参数使用的字符编码
     * @param charSet       返回结果二进制流转字符串使用的编码格式
     * @return String 请求返回信息
     * @author Kindey.S [kindey123@163.com]
     * @date 2020/6/7 13:21
     */
    public static String sendPost(String url
            , HashMap<String, String> pathParam
            , boolean encode, String encodeCharSet, String charSet) throws IOException {
        HashMap<String, String> headParam = new HashMap<>();

        headParam.put("accept", "*/*");
        headParam.put("connection", "Keep-Alive");
        headParam.put("Charsert", "UTF-8"); //设置请求编码
        headParam.put("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
        return sendPost(url, headParam, pathParam, encode, encodeCharSet, charSet);
    }

    /**
     * 发送post请求
     * 简化使用，只设置url
     * 请求头参数默认值：
     * accept=\*\/\*
     * connection=Keep-Alive
     * Charsert=UTF-8
     * user-agent=Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)
     *
     * @param url       请求路径
     * @param pathParam 路径参数
     * @param charSet   返回结果二进制流转字符串使用的编码格式
     * @return String 请求返回信息
     * @author Kindey.S [kindey123@163.com]
     * @date 2020/6/7 13:21
     */
    public static String sendPost(String url, HashMap<String, String> pathParam, String charSet) throws IOException {
        return sendPost(url, pathParam, false, "", charSet);
    }
}